[FFMPEG开发]音频转换后杂音、音画不同步、声音变快变慢的原因分析以及解决方法

您所在的位置:网站首页 音频 杂音 [FFMPEG开发]音频转换后杂音、音画不同步、声音变快变慢的原因分析以及解决方法

[FFMPEG开发]音频转换后杂音、音画不同步、声音变快变慢的原因分析以及解决方法

2024-07-15 19:44| 来源: 网络整理| 查看: 265

首先说句抱歉,距离上次说要写处理杂音问题,关于视频转换后视频明显变快变慢的内容在这里,有需求的可以看看帮忙点个赞ffmpeg的pts与音视频同步的关系   鸽了一个半月左右。本来想在整理好格式转换后就开始写帮助分析的,但是由于一直忙着实习跟自学一些东西一直没写。最近恰好遇到在做音频录制的事顺便也学了一些东西就一起总结下来把。

前言

首先在ffmpeg的音频编码中,中间数据都是pcm为主。在ffmpeg中一共支持这几种pcm编码格式

enum AVSampleFormat { AV_SAMPLE_FMT_NONE = -1, AV_SAMPLE_FMT_U8, ///< unsigned 8 bits AV_SAMPLE_FMT_S16, ///< signed 16 bits AV_SAMPLE_FMT_S32, ///< signed 32 bits AV_SAMPLE_FMT_FLT, ///< float AV_SAMPLE_FMT_DBL, ///< double AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar AV_SAMPLE_FMT_FLTP, ///< float, planar AV_SAMPLE_FMT_DBLP, ///< double, planar AV_SAMPLE_FMT_S64, ///< signed 64 bits AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically };

这几种都是常见的pcm采样存储方式。常用的音频编码使用FLTP跟S16居多,同时在ffmpeg中s16的存储是小端字节序存储的,这个是在使用SDL播放的时候发现的,所以一定需要知道自己采集的pcm格式才能进行转换存储。如果采集的pcm格式不在列表中就需要找其他库进行转换了。

基础储备

推荐看这个博主的博客pcm简介  由于pcm是编解码过程的中间格式,所以我们需要对pcm有一定了解,由于pcm的资料是在是太多了看百度百科知道个大概其实就可以了,除非是需要自己研究一些pcm数据处理否则没必要学那么多硬件处理上的内容。首先我们知道编码器有个参数是sample_rate,这个通常是对应pcm的采样频率,在以前使用8000hz较多ffmpeg的amr格式只支持8khz的采样,但是现在48khz跟44.1khz比较常见。在ffmpeg里带个p结尾的其实就是分声道进行存储不带p的就是混合存储,比如  双声道的s16(单位byte)就是1 1 2 2 1 1 2 2  双声道的s16p就是1 1 1 1 2 2 2 2 这里比较容易理解,我使用的SDL2没有s16p的接口,通常我都是需要转成s16再进行播放的。另外由于ffmpeg的帧大小是以采样率做单位,跟声道数无关,解码后的数据大小其实不是帧的大小这点需要注意,帧的存储大小的计算公式是  每帧存储大小=声道数*sizeof(存储格式)*采样率*byte  pcm数据其实已经将模拟信号转换成了数字信号算是原始的数据信息。只是每种存储格式表示上会有一些区别。有无符号,有符号,浮点,整形各种存法。至于怎么还原成声音还请百度找,内容比较多就不在这里解释了。

寻找问题

然后这里开始,有了上面的储备之后,就开始分析编码后与音源差异的问题了。  1.编码采样率与源采样率不一致,导致音频可能加快或者变慢  通常我们通过声卡设备采集或者直接将一些视频流,直播流的音频进行解码再编码。但是有些音频格式可能存在一些限制,可能导致前后采样率可能不一致。之前遇到的一个比较极端的例子就是amr格式编码限制为单声道8000hz编码,不知道是格式原因还是ffmpeg只提供了这个编码标准。由于aac编码通常都是44.1khz,所以我编码的时候发现声音貌似变慢了,用mediainfo一看,音频达到了视频的5倍时长,仔细看发现是amr只支持8000的采样,而我原先采样是44.1khz,我直接按44.1khz进行存储(我参考的ffmpeg官方例子的transcode_aac.c进行编写的,后面发现那个demo只支持同采样互转,当初没有发现这一点)。这个问题好解决,只需要稍改transcode_aac.c的代码,依旧使用SwrContext提供的方法进行转换。这里建议直接看源码,后续等我做完h.265的调研应该会写个视频音频抽取的小程序,如果实在不会,到时进行参考(如果假期我还有时间的话) 转换完了就是编码了,这里就涉及一个数学问题了,从44100->8000,采样的顺序就差不多是每5的点采一个点。做个比喻就是一个圆本来被分成了44100分,现在你只想把它分成8000分,一份表示的大小变大了,但是总大小依旧是一样的,1/44100变成了1/8000。采5份算个均值就差不多了(这是我的想法,由于没看ffmpeg的重采样源码,这里只是口胡,错了勿怪),这样声音就会保持一致了。至于为什么编码器为什么没有报错,我至今依旧没能理解这个问题,也许是ffmpeg的bug吧。  2.重采样没有正确叠加损失小数部分导致声音每段都会尖锐一下  这个问题很奇葩,同样是因为跨采样率导致的问题。首先我先问一个问题,44100能不能被8000整除,emmmm这个问题正常人心里都有答案了。从44100到8000的重采样,要怎么扔才扔的对,其实这个问题值得思考。ffmpeg编码的mp4通常是1024的SPF,每一帧1024个采样数据。我直接用av_rescale_q进行的转换,没有叠加,这就出现问题了,因为av_rescale_q没有记录余数的,也就是我每次都是向下取整。1024->185。44100每帧1024个声音数据43.06640625帧为1秒,而转换成8000采样每帧185个声音数据43.2432432帧为1秒,每秒都缺了数据,数字信号还原的时候合成的圆已经不是同样大小了声音出现了跳跃,导致听起来会有突然尖锐的杂音问题。这个问题要怎么解决,只要记录下采样点到哪了就可以了。因为向下取整的问题我们需要记录下次重采样应该采多大,可能一开始是185下一帧要采186最终才能合成同样大小的一个圆,所以应该这样采样1024->185 2048->371-185 3072->557-371…经过重算后就没有出现突然尖锐了。  3.封装的pts不正确,导致音视频不同步播放过程中如果不按快进可能音画同步,快进过后的视频就音画不同步了  这个问题首先请用mediainfo确认下两个的时长是不是一致的,如果是一致的,那就不是我描述的情况,如果音频时长明显长或者明显短,请注意下封包的时候处理下pts的问题。通常AVCodeContext->time_base是{1,44100}而AVFormatContext->stream[audio_output]->time_base却不一定是{1,44100}。之前在封装某个格式的时候发现了这个问题,所以在封装前一定要保持两者是一致的,如果不一致用av_rescale_q转换一下即可(目前没有发现两者不能通分的情况,所以请放心,转换后是可以直接封包的)。转换后就没有遇到过这个问题了。

总结

这是我开发过程中遇到的问题,感谢雷神给的资料,ffmepg的example源码,还有ffmpeg交流群跟带我的人的帮助,如果想要更深入学习ffmpeg这里推荐用vs编译一份源码进行调试,国外大神已经整理了目录了,只需要自己编译一下即可 ffmpeg vs项目整理如果不是win环境可以用makefile整理个目录,用Source Insight看,直接去github上clone一下ffmpeg的源码。 这份资料是一个学了四个月ffmpeg开发的菜鸟写的,如果有什么地方讲错了请见谅。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3